Testing的第一個切入點:單元測試。
本篇文章將針對單元測試進行簡介,主要內容包含了:
Why, What, Where, Who, When。
而How的部分,屬於實作,將於下一篇文章介紹工具與簡單的範例。
最後會提到「測試案例」所代表的意義與其重要性。
上一篇文章:[Day 1]TDD guidance
@前言
單元測試,是developer最該寫的測試程式,卻也是最容易被忽略的測試。
大家常碰到的測試相關問題是:
看完這幾篇單元測試的相關文章後,希望大家可以獲得一些想法,解決這些問題。
@Why
先舉幾個在開發上常見的問題:
這些問題,可以有哪些Unit Test相關的方式來解決:
總而言之,沒有被測試涵蓋到的程式碼,即使它可能是對的,也沒人敢拍胸脯保證。而有了測試案例來輔助說明與保護,至少可以拍胸脯保證,在這樣的測試案例下,這個物件的設定,肯定如同預期般執行。
而單元測試可以提供迴歸測試的保護,在每一次異動完程式,可以單鍵執行就知道是否破壞了原本對物件行為的預期。
單元測試可以透過一些輔助設計,來達到與外部環境、服務、相依隔絕,而僅測試該物件本身的邏輯,以及與外部的互動是否符合預期。
造成問題的測試案例,往往是最珍貴的,因為最具代表性,也最具價值。因為他提供了我們修正bug的方向以及指標。而針對發生問題的測試案例,來執行單元測試,馬上就可以知道是否是該物件的內部問題。
最後,單元測試由於具備與外界服務、相依隔絕的特性,所以可以幫助撰寫實際的物件時,具有可測試性、低耦合性,彼此之間只相依於抽象或介面。進而透過IoC的設計,讓我們可以做到關注點分離,讓開發各個物件的developer,可以透過介面來溝通,不相依於彼此實作,就能平行開發。
@What
Unit Test的定義與基本準則:
Unit Test的特性,一個字:FIRST
@Where
單元測試的範圍,以定義來說,單元測試是最小的測試單位,在物件導向中,就是測試一個方法。而方法一定會在某個物件上(即使是靜態方法,也是在型別物件上)。
所以,單元測試通常就只關注在測試的目標物件上,而不管目標物件以外的東西,例如:目標物件所相依的實體物件、相依服務、相依資源、相依環境等等...
單元測試,簡單的說,就是用來模擬外部如何使用這個目標物件,或是如何與這個目標物件互動。所以我們所撰寫的單元測試程式,就是模擬與目標物件互動的程式。測試案例,就是該互動下的情境。接著驗證物件的行為是否符合我們預期。
因此,單元測試程式,既然是模擬外部如何使用目標物件,所以也只會針對目標物件對外開放的方法。
而基本上,單元測試透過哪些方式去驗證物件的行為符合預期呢?簡單來說,有三種:
驗證目標物件的回傳值
驗證目標物件的狀態改變
驗證目標物件與外部相依介面的互動方式
@Who
單元測試該由誰來撰寫,就如同前言所說,最應該撰寫的是developer,而非QA/QE。
就如@Where段落所說,單元測試簡單的說,是我們在設計物件的時候,預期外部該如何使用這個物件,進而衍生出物件該提供什麼樣的功能、具備什麼樣的行為。正因為物件的設計人、使用人,都是developer,所以單元測試的程式,當然由developer來設計,最為妥當。尤其由用的人來寫,最為精準。
歸納幾個基本要點:
@When
撰寫單元測試的時機點,簡單分成三個:
想清楚,外部的需求是什麼,才能設計出符合需求的物件。
當需求異動時,自然需要針對新的需求,來設計新的測試程式,因為這樣才能驅使目標物件行為的改變。
當出現非預期的執行結果時,通常代表目標物件有著非預期的行為發生,有可能是當初測試案例不足,所以要增加我們的「預期」。
也有可能是當初預期的結果就錯了,那其實就可以當作是第二點,需求的異動。(當然對使用端來說,還是屬於bug,但對物件設計來說,測試案例方向就錯了,當然無法苛求目標物件的行為要對...測試程式與實際物件是一起活著的)
@Test Cases的意義
大家買過3C產品或電器吧,基本上拿到一個東西,我們都會先看使用說明書。
大家肯定也寫過一堆「系統分析書」、「程式規格書」、「SA/SD文件」等等...但這些文件,跟最後線上的程式碼,究竟有多少是相同的呢?文件越詳細,代表後面修改的effort越大。
因為軟體設計,本來就是個需求頻繁變動的過程,往往大家只想「凍結需求」,卻很常因為「凍結需求」搞到作出來的系統難用,因為不符合使用者需求。(我們期望的是,每一次的需求異動,都是軟體進化的動力,每一次的異動,都是品質的累積,以及更符合使用者的需求。)
而文件呢?只有一開始分析、設計爽的,因為程式碼寫下去,跟文件搭不搭的起來,只有三個人知道,一個已經離職了,一個是我,另一個我不能說。
鮮少會有文件跟著程式碼一直進行更新的。
但文件卻又是輔助瞭解與說明很重要的東西,那怎麼辦?很簡單,會一直活著的,就只有程式碼。要驗證程式碼是否符合我們預期,最簡單的方式,就是用程式碼驗證它的行為,一翻兩瞪眼,現在的物件究竟滿足了那些功能,哪些情境下可以跑出預期結果,測試案例一目了然。
所以,測試案例的意義與價值是什麼?
程式碼即文件,高興什麼時候產生文件,就什麼時候產生,保證即時、可運作、童叟無欺。測試案例上面有的,肯定work,而測試案例上面沒有的,不一定會錯,但不打包票。
@小結
一句話總結:「working software based on working test cases」
working software是TDD的整個骨架,也是user最需要的東西。
怎麼覺得樓主寫文章的風格好像一位IT前輩91哥的風格,連圖都很像
沒想到一眼就被看穿身份了。
這樣我就不能當蒙面加菲貓了啊!
樓主就是91哥阿
.....hatelove 就是91哥喔~
小的真是有演不是泰山啊~原來91哥會用不同的ID
<span style="color: green;"><span style="font-size: 36px;">頂.禮.膜.拜!</span></span>